#! coding=utf-8
import os
import json
import shutil
import hashlib
import platform
import subprocess
import io
import re
import sys
import plistlib
import time
from utils import logger
from datetime import datetime

log = logger.log
CUR_DIR = os.path.dirname(os.path.abspath(__file__)) + "/"



def get_filelist(dir, filelist, needEnter=True, file_ext=[]):
    newDir = dir
    if os.path.isfile(dir):
        if len(file_ext) > 0:
            
            for filetype in file_ext:
                if dir.endswith(filetype):
                    filelist.append(dir.replace("\\", "/"))
        else:
            filelist.append(dir.replace("\\", "/"))
    elif os.path.isdir(dir) and needEnter:
        for s in os.listdir(dir):
            newDir = os.path.join(dir, s)
            get_filelist(newDir, filelist,needEnter,file_ext)


def get_dirlist(dir, dirlist, needEnter=True):
    newDir = dir

    if os.path.isdir(dir) and needEnter:
        dirlist.append(dir.replace("\\", "/"))
        for s in os.listdir(dir):
            newDir = os.path.join(dir, s)
            get_dirlist(newDir, dirlist)


def get_file_name(filepath):
    filename = os.path.splitext(filepath)[0]
    arr = filename.split("/")
    return arr[len(arr) - 1]


def encript(tips):
    secret = []

    for v in tips:
        code = ord(v)
        if code >= 65 and code <= 90:
            if code == 90:
                code = 65
            else:
                code = code + 1
        elif code >= 97 and code <= 122:
            if code == 122:
                code = 97
            else:
                code = code + 1
        elif code >= 48 and code <= 57:
            if code == 57:
                code = 48
            else:
                code = code + 1
        try:
            secret.append(chr(code))
        except:
            log.error("error path:{}".format(tips))
    return "".join(secret).encode()


def decript(tips):

    secret = []
    for v in tips:
        code = ord(v)
        if code >= 65 and code <= 90:
            if code == 90:
                code = 65
            else:
                code = code - 1
        elif code >= 97 and code <= 122:
            if code == 97:
                code = 122
            else:
                code = code - 1
        elif code >= 48 and code <= 57:
            if code == 48:
                code = 57
            else:
                code = code - 1
        try:
            secret.append(chr(code))
        except:
            log.error("error path:{}".format())
    return "".join(secret).encode()


def encriptFile(source_dir, target_dir, filepath):
    filename = get_file_name(filepath)
    filedata = os.path.splitext(filepath)[0]
    filetype = filepath.replace(filedata, "")
    
    newfilepath = filepath.replace(source_dir, "")
    newfilepath = newfilepath.replace(filetype, "")

    newfilepath = encript(newfilepath)

    newfilepath = newfilepath + filetype
    # newfilepath = filepath.replace(filename +  filetype,"{}{}".format(encriptfilename,filetype))
    # newfilepath =  newfilepath.replace(source_dir,target_dir)
    # print(newfilepath)

    newfilepath = target_dir + newfilepath
    # print("encriptpath:" + newfilepath)
    newdir = os.path.dirname(newfilepath)

    if not os.path.exists(newdir):
        os.makedirs(newdir)
    shutil.copy(filepath, newfilepath)


def encodeDir(source_dir, target_dir):
    fileList = []
    get_filelist(source_dir, fileList)
    for filepath in fileList:
        encriptFile(source_dir, target_dir, filepath)


def writeFile(filepath, data):
    dirname = os.path.dirname(filepath)
    if not os.path.exists(dirname):
        make_dirs(dirname)
    f = open(filepath, "w", encoding="utf-8")
    f.write(data)
    f.close()
    log.info("write:{} success!".format(filepath))


def removeFile(filepath,showLog = True):
    if os.path.exists(filepath):
        os.remove(filepath)
        if showLog:
            log.info("remove filepath:{}".format(filepath))


def remove_dir(dirpath):
    if os.path.exists(dirpath):
        shutil.rmtree(dirpath)


def make_dirs(dirpath):
    if not os.path.exists(dirpath):
        os.makedirs(dirpath)


def getStringFromFile(filepath):
    if os.path.exists(filepath):
        f = open(filepath, "r", encoding='utf-8')
        text = f.read()
        f.close()
        return text
    else:
        return ""


def readFile(filepath):
    if os.path.exists(filepath):
        f = open(filepath, "r",encoding="utf-8")
        data = f.read()
        f.close()
        return data


def getFileJsonData(filepath):
    text = getStringFromFile(filepath)
    if text != "":
        return json.loads(text)


def getFileMD5(filepath):
    s = open(filepath, "rb").read()
    return hashlib.md5(s).hexdigest()


def getfileType(filepath):
    return filepath[filepath.rfind("."):]


def cmd(cmdstr):
    result = os.popen(cmdstr)
    return result


def readPlist(filepath):
    with open(filepath, "rb") as fp:
        return plistlib.load(fp)


def writePlist(data, filepath):
    with open(filepath, "wb") as fp:
        plistlib.dump(data, fp)


def copydir(source, target):
    if os.path.exists(target):
        shutil.rmtree(target)
    shutil.copytree(source, target)


def isWindows():
    return platform.system() == "Windows"


def get_dirs(dirpath, dir_list):

    if os.path.isdir(dirpath):
        for dir in os.listdir(dirpath):
            get_dirs(dir, dir_list)
        dir_list.append(dir)


def copyfile(source, target):
    if not os.path.exists(source):
        return
    dirpath = os.path.dirname(target)
    if not os.path.exists(dirpath):
        make_dirs(dirpath)

    shutil.copyfile(source, target)

# 合并文件夹资源


def merge_dirs(dirs, target_dir):
    remove_dir(target_dir)
    make_dirs(target_dir)
    target_dir = target_dir.replace("\\", "/")
    for dirpath in dirs:
        dirpath = dirpath.replace("\\", "/")
        if not os.path.exists(dirpath):
            continue

        fileList = []
        get_filelist(dirpath, fileList)

        for filepath in fileList:
            relativepath = os.path.relpath(filepath, dirpath)
            nefilepath = os.path.join(target_dir, relativepath)
            if os.path.exists(nefilepath):
                removeFile(nefilepath)
            copyfile(filepath, nefilepath)

# 更新plist的值


def update_plist_value(plistpath, key, value):
    if not os.path.exists(plistpath):
        return

    contents = readPlist(plistpath)
    contents[key] = value
    writePlist(contents, plistpath)


def bytes_str(bytes):
    if bytes < 1024:  # 比特
        bytes = str(round(bytes, 2)) + ' B'  # 字节
    elif bytes >= 1024 and bytes < 1024 * 1024:
        bytes = str(round(bytes / 1024, 2)) + ' KB'  # 千字节
    elif bytes >= 1024 * 1024 and bytes < 1024 * 1024 * 1024:
        bytes = str(round(bytes / 1024 / 1024, 2)) + ' MB'  # 兆字节
    elif bytes >= 1024 * 1024 * 1024 and bytes < 1024 * 1024 * 1024 * 1024:
        bytes = str(round(bytes / 1024 / 1024 / 1024, 2)) + ' GB'  # 千兆字节
    elif bytes >= 1024 * 1024 * 1024 * 1024 and bytes < 1024 * 1024 * 1024 * 1024 * 1024:
        bytes = str(round(bytes / 1024 / 1024 / 1024 / 1024, 2)) + ' TB'  # 太字节
    elif bytes >= 1024 * 1024 * 1024 * 1024 * 1024 and bytes < 1024 * 1024 * 1024 * 1024 * 1024 * 1024:
        bytes = str(round(bytes / 1024 / 1024 / 1024 /
                    1024 / 1024, 2)) + ' PB'  # 拍字节
    elif bytes >= 1024 * 1024 * 1024 * 1024 * 1024 * 1024 and bytes < 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024:
        bytes = str(round(bytes / 1024 / 1024 / 1024 /
                    1024 / 1024 / 1024, 2)) + ' EB'  # 艾字节
    return bytes


def get_file_size_str(filepath):
    if not os.path.exists(filepath):
        return "0"

    return bytes_str(os.stat(filepath).st_size)


def get_file_size(filepath):
    return os.stat(filepath).st_size


def get_svn_author(svnpath):
    # 执行 svn info 命令，并获取输出
    proc = subprocess.Popen(
        ["svn", "info"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=svnpath)
    output, error = proc.communicate()

    # 解码输出，获取提交者名字
    output = io.TextIOWrapper(io.BytesIO(output), encoding="utf-8").read()
    author = None
    try:
        author = output.split("\n")[9].split(":")[1].strip()
        # for line in output.split("\n"):
        #     if line.startswith("最后修改的作者:"):
        #         author = line.split(":")[1].strip()
    except:
        return author

    return author


def commit_svn_delete_list(svndir):
    deleted_files = []

    cmd = "svn status {} | grep '^D' | awk '{print $2}'".format(svndir)
    # 执行 svn status 命令
    output = subprocess.check_output(cmd)

    deleted_files = output.splitlines()

    # 输出被删除的文件或目录
    log.info(deleted_files)

    return deleted_files


def get_svn_version(svnpath):
    if os.path.exists(svnpath):
        cmd = ["svn", "info", svnpath, "--show-item", "last-changed-revision"]
        try:
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            if result.returncode == 0:
                curversion = result.stdout.strip()
                if curversion:
                    curversion = str(int(curversion))
                return curversion
            else:
                log.error("SVN command failed with error:", result.stderr)
                return ""
        except Exception as e:
            print(svnpath)
            log.error("An error occurred:", str(e))
            return ""
    else:
        return ""

# 获取系统平台


def get_sys_platform():
    if sys.platform == "win32":
        return "win32"

    else:
        return "mac"

# 获取git最后一次提交的hash


def get_git_version(gitpath):

    try:
        # 运行Git命令获取最后一次提交的哈希值
        result = subprocess.check_output(
            ['git', 'rev-parse', "--short=6", 'HEAD'], universal_newlines=True, cwd=gitpath)
        return result.strip()  # 去除末尾的换行符
    except subprocess.CalledProcessError as e:
        log.error(f"Error: {e}")

        return ""
    else:
        return ""


def svn_update(dir):

    is_win32 = get_sys_platform() == "win32"
    log.info(f"svn dir {dir} update...")
    if is_win32:
        os.system("cd {} && svn update".format(dir))
        # subprocess.check_output(['svn','update'], universal_newlines=True,cwd=dir)
    else:
        subprocess.check_output(['svn', 'update'], universal_newlines=True, cwd=dir)
# exts:[".lua",".png"]


def clear_file_by_ext(dir, exts):
    file_list = []

    get_filelist(dir, file_list)

    for filepath in file_list:
        file_type = getfileType(filepath)
        if filepath.endswith(file_type):
            removeFile(filepath)


def get_time():
    now = datetime.now()
    return now.strftime("%Y%m%d%H%M")

# 检查svn目录是否有冲突或者修改


def is_svn_nothave_change(svndir):
    try:
        result = subprocess.run(
            ['svn', 'status', svndir], capture_output=True, text=True, check=True)
        output = result.stdout
        if "M" in output:
            return False

        if "A" in output:
            return False

        if "D" in output:
            return False

        if "C" in output:
            return False

    except subprocess.CalledProcessError as e:
        log.error(f"命令行执行失败:{e.stderr}")
    except FileNotFoundError:
        log.error("svn tools not found")

# 合并某个文件到某个目录


def merge_dir(dir, target_dir):
    if not os.path.exists(target_dir):
        make_dirs(target_dir)
    file_list = []
    get_filelist(dir, file_list)
    log.info(f"merge dir {dir}  {target_dir}")
    for filepath in file_list:
        relavie_filepath = os.path.relpath(filepath,dir)
        target_filepath = target_dir + "/" + relavie_filepath
        dirname = os.path.dirname(target_filepath)
        if not os.path.exists(dirname):
            make_dirs(dirname)
        shutil.copy2(filepath, target_filepath)
        


def conver_ogg(filepath):
    ffmpeg_exe = CUR_DIR + "../plugins/ffmpeg/bin/ffmpeg.exe"
    ogg_filepath = filepath.replace(".mp3", ".ogg")
    cmd = f"{ffmpeg_exe} -i {filepath} -c:a libvorbis {ogg_filepath}"
    os.system(cmd)
    log.info(cmd)
    if os.path.exists(ogg_filepath):
        removeFile(filepath)
# mp3转ogg


def conver_mp3_to_ogg(dir):

    file_list = []
    get_filelist(dir, file_list)

    for filepath in file_list:
        filetype = getfileType(filepath)

        if filetype != ".mp3":
            continue
        conver_ogg(filepath)


#提交某个目录
def svn_commit(dir,commit_message):
    try:
        command = ['svn','commit','-m',commit_message,dir]
        
        #执行svn提交命令
        result = subprocess.run(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)
        if result.returncode == 0:
            log.info(f"{dir} svn commit success")
            return True
        else:
            log.error(f"{dir} svn commit failed {result.stderr}")
            return False
    except Exception as e:
        log.error(f"Errror during svn commit: {e}")
        return False

def svn_add(dir):
    try:
        command = ['svn','add','--force',dir]
        
        #执行svn提交命令
        result = subprocess.run(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)
        if result.returncode == 0:
            log.info(f"{dir} svn add success")
            return True
        else:
            log.error(f"{dir} svn add failed {result.stderr}")
            return False
    except Exception as e:
        log.error(f"Errror during svn add: {e}")
        return False
    


def svn_update_and_revert(directory):
    # 执行 svn update 命令
    update_command = f"svn update {directory}"
    update_process = subprocess.Popen(update_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    update_output, update_error = update_process.communicate()

    # 检查命令是否执行成功
    if update_process.returncode != 0:
        print(f"svn update failed with error: {update_error.decode()}")
        return -1

    # 检查目录是否有修改、冲突或新增文件
    status_command = f"svn status {directory}"
    status_process = subprocess.Popen(status_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    status_output, status_error = status_process.communicate()

    if status_process.returncode != 0:
        print(f"svn status failed with error: {status_error.decode()}")
        return -2

    # 检查输出中是否包含修改、冲突或新增的标记
    if "M" in status_output.decode() or "C" in status_output.decode() or "?" in status_output.decode():
        # 执行整个目录的 svn revert
        revert_command = f"svn revert -R {directory}"
        revert_process = subprocess.Popen(revert_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        revert_output, revert_error = revert_process.communicate()

        if revert_process.returncode != 0:
            print(f"svn revert failed with error: {revert_error.decode()}")
            return -3

        print("Reverted the directory successfully.")
    else:
        print("No modifications, conflicts, or additions found in the directory.")

    return 0

#获取文件修改时间
def get_file_changetime(filepath):

    # 获取文件的修改时间
    modification_time = os.path.getmtime(filepath)


    

    return modification_time

#解压zip包
def unzip(zip_path,dir):
    shutil.unpack_archive(zip_path,dir,"zip")

def dump_methods(obj):
    methods = [method for method in dir(obj) if callable(getattr(obj,method))]
    for method in methods:
        print(method)